<?php

namespace nimo\common\models;

use nimo\common\develop\Profiler;
use ArrayAccess;
use Carbon\Carbon;
use DateTime;
use JsonSerializable;
use LogicException;
use Illuminate\Database\ConnectionResolverInterface as Resolver;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\Relations\MorphMany;
use Illuminate\Database\Eloquent\Relations\MorphOne;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Database\Eloquent\Relations\MorphToMany;
use Illuminate\Database\Eloquent\Relations\Pivot;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Eloquent\ScopeInterface;
use Illuminate\Database\Query\Builder as QueryBuilder;
use Illuminate\Events\Dispatcher;
use Illuminate\Support\Contracts\ArrayableInterface;
use Illuminate\Support\Contracts\JsonableInterface;
use Illuminate\Database\Eloquent\SoftDeletingScope;

// $this->setRawAttributes($fresh->getAttributes(), true);
trait MultiKeyTrait {
    // ------------------------------
    // customized function
    // ------------------------------
    function getJointPk() {
        $s = array();
        foreach ( $this->primaryKey as $key ) {
            $s[] = $this->getAttribute($key);
        }
        return implode('-', $s);
    }
    public function findByJointPK($joint, $columns = array('*')) {
        $keys = explode('-', $joint);
        $query = $this->query();
        for($i = 0; $i < count($this->primaryKey); $i ++) {
            $query = $query->where($this->primaryKey[$i], '=', ($i < count($keys)) ? $keys[$i] : '');
        }
        return $query->first($columns);
    }
    public function findByJointPKOrFail($joint, $columns = array('*')) {
        if (! is_null($model = $this->findByJointPK($joint, $columns)))
            return $model;
        throw new ModelNotFoundException();
    }
    // ------------------------------
    // laravel framework function
    // ------------------------------
    // protected static function bootTraits() { parent::bootTraits(); }
    public static function bootSoftDeletingTrait() {
        if (static::$softDeletesEnabled) {
            static::addGlobalScope(new SoftDeletingScope);
        }
        $exists = static::hasGlobalScope(new SoftDeletingScope());
        if ($exists && !static::$softDeletesEnabled || !$exists && static::$softDeletesEnabled) {
            throw new \Exception('make sure $softDeletesEnabled for SoftDeletingTrait');
        }
    }
    public static function hasGlobalScope($scope) {
        return array_key_exists (get_called_class(), static::$globalScopes) && parent::hasGlobalScope($scope);
    }
    protected function getKeyForSaveQuery(){
        $keyname = $this->getKeyName();
        if (!is_array($keyname)) {
            return parent::getKeyForSaveQuery();
        }
        if (count($this->original)>0) {
            return array_intersect_key($this->original, array_flip($keyname));
        }
        return array_intersect_key($this->attributes, array_flip($keyname));
    }
    protected function setKeysForSaveQuery(Builder $query){
        $keys = $this->getKeyForSaveQuery();
        if (!is_array($keys)) {
            return parent::setKeysForSaveQuery($query);
        }
        //$table = $this->getTable();
        foreach ($keys as $key => $value) {
            $query->where($key, '=', $value);
        }
        return $query;
    }
    public function isFillable($key) {
        $ret = parent::isFillable($key);
        if (! $ret && ! $this->incrementing) {
            // guarded primary key should be set
            if ($key == $this->primaryKey || in_array($key, $this->primaryKey)) {
                return true;
            }
        }
        return $ret;
    }
    public static function find($id, $columns = array('*')) {
        if (is_array($id)) {
            $instance = static::firstByAttributes($id);
        } else {
            $instance = parent::find($id);
        }
        return $instance;
    }
    public function getKey() {
        $keyname = $this->getKeyName();
        if (is_array($keyname)) {
            $keys = array_intersect_key($this->attributes, array_flip($keyname));
        } else {
            $keys = $this->getAttribute($keyname);
        }
        return $keys;
    }
    public function getKeyName() {
        if ($this->incrementing && is_array($this->primaryKey)) {
            throw new \Exception("Bad incremental primary key defined on model.");
        }
        return $this->primaryKey;
    }
    // ------------------------------
    // baum node framework function
    // ------------------------------
    protected static $softDeletesEnabled = false;
    public function areSoftDeletesEnabled() {
        return static::$softDeletesEnabled;
    }
    public static function softDeletesEnabled() {
        return static::$softDeletesEnabled;
    }
}
